using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
using System.Xml.Serialization;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Workflow;
using System.Collections;
using System.Web.UI;

namespace MP.SharePoint.Workflow
{
    [XmlRoot(Namespace="http://mp/sharepoint/")]
    public class ManageReceivers : WebPart
    {
        DropDownList lists;
        DropDownList workflows;
        DropDownList events;
        Button addReceiver;
        Table remove;
        Label eventLbl;
        Label workflowLbl;

        string overallException = string.Empty;

        Literal Break
        {
            get
            {
                Literal lit = new Literal();
                lit.Text = "<br />";
                return lit;
              
            }


        }

        Label CreateLabel(string text, bool bold)
        {
            Label lbl = new Label();
            lbl.Text = text;

            
                lbl.Font.Bold = bold;

            return lbl;


        }
        protected override void CreateChildControls()
        {
            try
            {
                overallException = string.Empty;

                base.CreateChildControls();

                SPWeb web = SPControl.GetContextWeb(this.Context);
                Table table = new Table();
                lists = new DropDownList();

                lists.Items.AddRange(GetLists(web.Lists));
                
                lists.SelectedIndexChanged += new EventHandler(lists_SelectedIndexChanged);

                lists.AutoPostBack = true;
                TableRow tr = new TableRow();
                tr.Cells.Add(CellWithControl(CreateLabel("List", true)));
                 tr.Cells.Add(CellWithControl(lists));
                 table.Rows.Add(tr);
                events = new DropDownList();
                events.Visible = false;
                eventLbl = CreateLabel("Event", true);
                eventLbl.Visible = false;
                TableRow tr1 = new TableRow();
                   tr1.Cells.Add(CellWithControl(eventLbl));
                tr1.Cells.Add(CellWithControl(events));
                table.Rows.Add(tr1);
                workflows = new DropDownList();
                workflows.Visible = false;
                workflowLbl = CreateLabel("Workflow", true);
                workflowLbl.Visible = false;
                TableRow tr2 = new TableRow();
               tr2.Cells.Add(CellWithControl(workflowLbl));
                 tr2.Cells.Add(CellWithControl(workflows));
             
                table.Rows.Add(tr2);
                this.Controls.Add(table);
                addReceiver = new Button();
                addReceiver.Visible = false;

                addReceiver.Text = "Add";
                addReceiver.Click += new EventHandler(addReceiver_Click);
                this.Controls.Add(addReceiver);
                this.Controls.Add(Break);
                remove = ExistingReceivers(web);
                this.Controls.Add(remove);  


            }
            catch (Exception ex)
            {
                overallException += ex.GetType().Name + ": " + ex.Message;

            }
        }

        const string assembly = "MP.SharePoint.Workflow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=63312cf16c29a9a9";
        const string className = "MP.SharePoint.Workflow.WFReceiver";

        SPWorkflowAssociation GetWorkflowAssociation(string type, SPList list, SPWeb web)
        {
            return list.WorkflowAssociations[new Guid(web.Properties[list.ID.ToString() + ";" + type])];


        }

        TableCell CellWithControl(Control control)
        {
            TableCell cell = new TableCell();
            cell.Controls.Add(control);
            return cell;


        }

        Table ExistingReceivers(SPWeb web)
        {
            web.AllowUnsafeUpdates = true;

            Table ret = new Table();
            ret.BorderStyle = BorderStyle.Groove;
            

            TableRow header = new TableRow();
            header.BorderStyle = BorderStyle.Inset;
            header.Cells.Add(new TableCell());
            header.Cells.Add(CellWithControl(CreateLabel("List", true)));
            header.Cells.Add(CellWithControl(CreateLabel("Event", true)));
            header.Cells.Add(CellWithControl(CreateLabel("Workflow", true)));
       
         
            ret.Rows.Add(header);


            for (int i = 0; i < web.Lists.Count; i++ )
            {
                SPList list = web.Lists[i];

                List<Guid> orphans = new List<Guid>();

                foreach (SPEventReceiverDefinition receiver in list.EventReceivers)
                {
                    if (receiver.Class == className)
                    {

                        if (!web.Properties.ContainsKey(list.ID.ToString() + ";" + receiver.Type.ToString()))
                        {
                            orphans.Add(receiver.Id);
                            continue;
                        }


                        TableRow tr = new TableRow();
                   
                        Button remove = new Button();

                        remove.Text = "Remove";

                        remove.Click += new EventHandler(remove_Click);

                        string type = receiver.Type.ToString();

                        ButtonValue buttonValue = new ButtonValue();

                        SPWorkflowAssociation assoc = GetWorkflowAssociation(type, list, web);

                        buttonValue.ReceiverId = receiver.Id;
                        buttonValue.EventType = receiver.Type;
                        buttonValue.ListId = list.ID;
                        buttonValue.WorkflowId = assoc.Id;

                        remove.ID = buttonValue.GetButtonId();

                        tr.Cells.Add(CellWithControl(remove));
                        tr.Cells.Add(CellWithControl(CreateLabel(list.Title, false)));
                        tr.Cells.Add(CellWithControl(CreateLabel(type, false)));
                        tr.Cells.Add(CellWithControl(CreateLabel(assoc.Name, false)));
                  

                     

                      

               

                        ret.Rows.Add(tr);
                    }


                }

                foreach (Guid id in orphans)
                {
                    list.EventReceivers[id].Delete();


                }

            }
            web.AllowUnsafeUpdates = false;
            return ret;

        }

        void remove_Click(object sender, EventArgs e)
        {
            try
            {
                Button removeButton = (Button)sender;
                ButtonValue values = new ButtonValue(removeButton.ID);

                SPWeb web = SPControl.GetContextWeb(this.Context);

                web.Lists[values.ListId].EventReceivers[values.ReceiverId].Delete();

                web.Properties.Remove(values.GetPropertyKey());

                web.Properties.Update();

                this.Context.Response.Redirect(Context.Request.Url.ToString());

            }
            catch (Exception ex)
            {
                overallException += ex.GetType().Name + ": " + ex.Message;

            }
        }


        void addReceiver_Click(object sender, EventArgs e)
        {
            try{

            SPWeb web = SPControl.GetContextWeb(this.Context);

            SPList list = web.Lists[new Guid(lists.SelectedValue)];
string key = lists.SelectedValue + ";" + events.SelectedValue;
                if(web.Properties.ContainsKey(key))
                    web.Properties.Remove(key);

            web.Properties.Add(key, workflows.SelectedValue);

            web.Properties.Update();

            list.EventReceivers.Add((SPEventReceiverType)Enum.Parse(typeof(SPEventReceiverType), events.SelectedValue), assembly, className);

            this.Context.Response.Redirect(Context.Request.Url.ToString());


              }
            catch (Exception ex)
            {
                overallException += ex.GetType().Name + ": " + ex.Message;

            }
        }

        void lists_SelectedIndexChanged(object sender, EventArgs e)
        {
            try{
       
            workflows.Items.Clear();
            events.Items.Clear();

             SPWeb web = SPControl.GetContextWeb(this.Context);
            SPList list = web.Lists[new Guid(lists.SelectedValue)];
            
           
            workflows.Items.AddRange(GetWorkflows(list.WorkflowAssociations));

           
          
            events.Items.AddRange(GetAvailibleEvents(list.EventReceivers));

            if (workflows.Items.Count < 1)
            {
                workflows.Visible = false;
                events.Visible = false;
                addReceiver.Visible = false;
                eventLbl.Visible = false;
                workflowLbl.Visible = false;

                overallException = "There are no workflows associated with this list.";

            }
            else if (events.Items.Count < 1)
            {
                workflows.Visible = false;
                events.Visible = false;
                addReceiver.Visible = false;
                eventLbl.Visible = false;
                workflowLbl.Visible = false;
                overallException = "There are no availible events to associate with a workflow.";


            }
            else
            {
                workflows.Visible = true;
                events.Visible = true;
                addReceiver.Visible = true;
                eventLbl.Visible = true;
                workflowLbl.Visible = true;
            }

        }
        catch (Exception ex)
        {
            overallException += ex.GetType().Name + ": " + ex.Message;

        }
        }


        protected override void RenderWebPart(System.Web.UI.HtmlTextWriter output)
        {
            if (!string.IsNullOrEmpty(overallException))
                output.Write(overallException + "<br /><br />");

            base.RenderWebPart(output);


        }


        ListItem[] GetAvailibleEvents(SPEventReceiverDefinitionCollection events)
        {
            ArrayList ret = GetAllItemEvents;

            foreach (SPEventReceiverDefinition evant in events)
            {
                ListItem type = new ListItem(evant.Type.ToString());

                if (ret.Contains(type))
                    ret.Remove(type);

            }

           return (ListItem[])ret.ToArray(typeof(ListItem));
        }


        ArrayList GetAllItemEvents
        {
            get
            {
                ArrayList al = new ArrayList();

                foreach (string type in Enum.GetNames(typeof(SPEventReceiverType)))
                {
                    if(type.Contains("Item"))
                    al.Add(new ListItem(type));
                }
                return al;


            }


        }


        ListItem[] GetWorkflows(SPWorkflowAssociationCollection workflows)
        {
            int count = workflows.Count;

            ListItem[] ret = new ListItem[count];

            for (int i = 0; i < count; i++)
            {


                SPWorkflowAssociation workflow = workflows[i];
                
                ret[i] = new ListItem(workflow.Name, workflow.Id.ToString());

            }

            return ret;


        }


        ListItem[] GetLists(SPListCollection listCollection)
        {
            int count = listCollection.Count;

            ListItem[] ret = new ListItem[count];

           for(int i = 0; i < count; i++)
           {
               

            SPList list =    listCollection[i];

               ret[i] = new ListItem(list.Title, list.ID.ToString());

           }

            return ret;


               
            


        }



    }

   internal class ButtonValue
    {
       internal ButtonValue()
       { }

       internal ButtonValue(string buttonId)
        {
            string[] values = buttonId.Split(';');

         ListId =   new Guid(values[0]);

         EventType = (SPEventReceiverType)Enum.Parse(typeof(SPEventReceiverType), values[1]);

         WorkflowId = new Guid(values[2]);

         ReceiverId = new Guid(values[3]);

        }

       internal Guid ListId = Guid.Empty;

       internal Guid ReceiverId = Guid.Empty;

       internal SPEventReceiverType EventType = SPEventReceiverType.InvalidReceiver;

       internal Guid WorkflowId = Guid.Empty;

       internal string GetButtonId()
       {
           ValidateAll();

          
           StringBuilder sb = new StringBuilder();
           sb.Append(ListId);
           sb.Append(';');
           sb.Append(EventType);
           sb.Append(';');
           sb.Append(WorkflowId);
           sb.Append(';');
           sb.Append(ReceiverId);
           return sb.ToString();



       }

       void ValidateAll()
       {
           if (ReceiverId == Guid.Empty || ListId == Guid.Empty || EventType == SPEventReceiverType.InvalidReceiver || WorkflowId == Guid.Empty)
               throw new ArgumentNullException("There is insufficient data to correctly build the button's Id");

       }

       internal string GetPropertyKey()
       {
           if (ListId == Guid.Empty || EventType == SPEventReceiverType.InvalidReceiver)
               throw new ArgumentNullException("There is insufficient data to correctly build the property key");


           StringBuilder sb = new StringBuilder();
           sb.Append(ListId);
           sb.Append(';');
           sb.Append(EventType);
        

           return sb.ToString();



       }


    }

}
